package cn.cboard.gateway;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;


/**
 * @author
 *
 * 
 * This lightweight class denotes a read-only logical view 
 * 
 * Interested subsystems should create instances of this class to describe the view
 * that they are interested in querying/fetching from.
 * 
 * The ViewDefnFactory class provides helper methods for createing desciptors
 * from configuration files. 
 * 
 * @see ViewDefnFactory
 */

public class ViewDefn implements SQLDefn {
	protected int maxRows;
	protected int fetchSize;
	protected ResultSetConverter converter;
	protected Object[] params;
	protected String viewName;
	protected String[] columnNames;
	protected WhereDesc[] wherePhrases;
	protected ColumnDesc[] orderBy;
	protected Map paramMap;

	public ViewDefn() {
		maxRows = -1;
		fetchSize = -1;
		converter = null;
		params = new Object[0];
		columnNames = new String[] { "*" };
		wherePhrases = null;
		orderBy = null;
		paramMap = null;
	}

	public ViewDefn(ViewDefn desc) {

		this.converter = desc.converter;
		this.params = desc.params;
		this.maxRows = desc.maxRows;
		this.fetchSize = desc.fetchSize;
		this.viewName = desc.viewName;
		this.wherePhrases = desc.wherePhrases;
		this.orderBy = desc.orderBy;
		this.columnNames = null;
		if (desc.columnNames != null) {
			this.columnNames = new String[desc.columnNames.length];
			for (int i = 0; i < desc.columnNames.length; i++)
				this.columnNames[i] = desc.columnNames[i];
		}
	}

	public ViewDefn(String viewName) {
		this();
		this.viewName = viewName;
	}

	public ViewDefn(String viewName, String[] columnNames) {
		this(viewName);
		this.columnNames = columnNames;
	}

	public ViewDefn(
		String viewName,
		String[] columnNames,
		String whereClause) {
		this(viewName, columnNames);
		this.wherePhrases = new WhereDesc[] { new WhereDesc(whereClause)};
	}

	public ViewDefn(
		String viewName,
		String[] columnNames,
		String whereClause,
		ColumnDesc[] orderBy) {
		this(viewName, columnNames, whereClause);
		this.orderBy = orderBy;
	}

	/**
	 * Returns the columnNames.
	 * @return String[]
	 */
	public String[] getColumnNames() {
		return columnNames;
	}

	/**
	 * Returns the viewName.
	 * @return String
	 */
	public String getViewName() {
		return viewName;
	}

	/**
	 * Sets the columnNames.
	 * @param columnNames The columnNames to set
	 */
	public void setColumnNames(String[] columnNames) {
		this.columnNames = columnNames;
	}

	/**
	 * Sets the viewName.
	 * @param viewName The viewName to set
	 */
	public void setViewName(String viewName) {
		this.viewName = viewName;
	}

	public String getSql(boolean reverse) {
		StringBuffer buf = new StringBuffer("SELECT ");
		
		
		for (int i = 0; i < columnNames.length; ++i) {
			buf.append(columnNames[i]);
			if (i < (columnNames.length - 1)) {
				buf.append(",");
			} //fi
		} // rof
		buf.append(" FROM ");
		buf.append(viewName);
		String wh = getWhereClause();
		if (wh != null) {
			buf.append(" WHERE ");
			buf.append(wh);
		} // fi

		ColumnDesc[] orders = getOrderBy();
		if (orders != null) {

			buf.append(" ORDER BY ");
			for (int i = 0; i < orders.length; ++i) {
				ColumnDesc col = orders[i];
				buf.append(col.getAsOrderBy(reverse));
				if (i < (orders.length - 1)) {
					buf.append(",");
				} //fi
			} //rof
		} // fi
		return buf.toString();
	}

	public String getSQL(boolean reverse) {
		return getSql(reverse);
	}
	
	public String getSQL() {
			return getSql(false);
		}


   
	public Object[] getParams() {
		if (paramMap == null) {
			return params;
		} else {
			// convert map into an Array
			ArrayList params = new ArrayList();

			for (int i = 0; i < wherePhrases.length; ++i) {
				WhereDesc d = wherePhrases[i];
				Collection c = d.getNamedParams(paramMap);
				params.addAll(c);
			} //rof

			return params.toArray();
		}

	}
	/**
	 * Returns the whereClause.
	 * @return String
	 */
	public String getWhereClause() {
		StringBuffer b = new StringBuffer();

		Object[] params = this.params;
		int index = 0;
		if (wherePhrases == null) {
			return null;
		}

		for (int i = 0; i < wherePhrases.length; ++i) {
			WhereDesc d = wherePhrases[i];
			String wh = null;

			if (paramMap != null) {
				// Use param name/value Map
				wh = d.getWhereClause(paramMap);

			} else {
				// Use ordered param list
				wh = d.getWhereClause(params, index);
			}

			if (wh != null) {
				b.append(' ');
				b.append(wh);
			}

			index = index + d.getNumberOfParams();

		} //rof

		return b.toString();
	}

	/**
	 * Sets the whereClause.
	 * @param whereClause The whereClause to set
	 */
	public void setWhereClause(String whereClause) {
		if (whereClause == null) {
			this.wherePhrases = null;
		} else {
			this.wherePhrases = new WhereDesc[] { new WhereDesc(whereClause)};
		}
	}

	/**
	 * Returns the orderBy.
	 * @return ColumnDesc[]
	 */
	public ColumnDesc[] getOrderBy() {
		return orderBy;
	}

	/**
	 * Sets the orderBy.
	 * @param orderBy The orderBy to set
	 */
	public void setOrderBy(ColumnDesc[] orderBy) {
		this.orderBy = orderBy;
	}

	/**
	 * Returns the wherePhrases.
	 * @return WhereDesc[]
	 */
	public WhereDesc[] getWherePhrases() {
		return wherePhrases;
	}

	/**
	 * Sets the wherePhrases.
	 * @param wherePhrases The wherePhrases to set
	 */
	public void setWherePhrases(WhereDesc[] wherePhrases) {
		this.wherePhrases = wherePhrases;
	}

	public void addWherePhrase(WhereDesc wherePhrase) {
		if (wherePhrases == null) {
			wherePhrases = new WhereDesc[] { wherePhrase };
		} else {
			WhereDesc[] newWherePhrases =
				new WhereDesc[this.wherePhrases.length + 1];
			System.arraycopy(
				wherePhrases,
				0,
				newWherePhrases,
				0,
				wherePhrases.length);
			newWherePhrases[wherePhrases.length] = wherePhrase;
			wherePhrases = newWherePhrases;
		}
	}

	public String getSQLForTotal() {
		StringBuffer sql = new StringBuffer("SELECT COUNT(*) from ");
		sql.append(viewName);
		String wh = getWhereClause();
		if (wh != null) {
			sql.append(" WHERE ");
			sql.append(wh);
		} // fi
		return sql.toString();
	}

	public void setNamedParameters(Map parameters) {
		this.paramMap = parameters;
	}

	/**
	 * @return
	 */
	public ResultSetConverter getConverter() {
		return converter;
	}

	/**
	 * @return
	 */
	public int getFetchSize() {
		return fetchSize;
	}

	/**
	 * @return
	 */
	public int getMaxRows() {
		return maxRows;
	}

	/**
	 * @return
	 */
	public Map getParamMap() {
		return paramMap;
	}

	/**
	 * @param converter
	 */
	public void setConverter(ResultSetConverter converter) {
		this.converter = converter;
	}

	/**
	 * @param i
	 */
	public void setFetchSize(int i) {
		fetchSize = i;
	}

	/**
	 * @param i
	 */
	public void setMaxRows(int i) {
		maxRows = i;
	}

	/**
	 * @param map
	 */
	public void setParamMap(Map map) {
		paramMap = map;
	}

	/**
	 * @param objects
	 */
	public void setParams(Object[] objects) {
		params = objects;
	}

}
